﻿#include "Graph2D.h"
#include "ElaMessageBar.h"
#include "Graph2DSettings.h"
#include "ElaTheme.h"
#include "SelectDatatDialog.h"
#include "DataChosenListDialog.h"
#include "Curve2DPlotor.h"
#include "TextFileParser.h"

namespace
{
    void normalizeAndLog(QVector<double>& vec, bool isNor, bool isLog)
    {
        if (vec.isEmpty() || (!isNor && !isLog))
        {
            return;
        }

        if (isNor && !isLog)
        {
            auto minmax_iter = std::minmax_element(vec.begin(), vec.end());
            double min_value = *minmax_iter.first;  // 最小值  
            double max_value = *minmax_iter.second; // 最大值 
            for (auto& i : vec)
            {
                i /= max_value;
            }
            return;

        }
        if (!isNor && isLog)
        {
            for (auto& i : vec)
            {
                i = 10 * std::log10(i);
            }
            return;
        }
        if (isNor && isLog) //先归一化再取对数
        {
            auto minmax_iter = std::minmax_element(vec.begin(), vec.end());
            double min_value = *minmax_iter.first;  // 最小值  
            double max_value = *minmax_iter.second; // 最大值 

            for (auto& i : vec)
            {
                i = 10 * std::log10(i / max_value);
            }
        }
    }
}

namespace pst
{
    Graph2D::Graph2D(QWidget* parent) :
        QWidget(parent)
    {
        QHBoxLayout* layout = new QHBoxLayout(this);
        layout->setContentsMargins(0, 0, 0, 0);
        layout->setStretch(0, 1);
        layout->setStretch(1, 0);
        m_colorList << QColor{ 255, 0, 0 }
            << QColor{ 0,255,0 }
            << QColor{ 0,0,255 }
            << QColor{ 128,158,173 }
            << QColor{ 0,128,0 }
            << QColor{ 255,69,0 }
            << QColor{ 255,0,255 }
            << QColor{ 127,255,0 }
            << QColor{ 153,50,204 }
            << QColor{ 255,140,0 }
            << QColor{ 155,93,112 }
            << QColor{ 240,128,128 }
            << QColor{ 0,111,255 }
            << QColor{ 0,0,128 }
        << QColor{ 128,0,128 };

        ///// @brief 测试代码
        //QStringList _thetaComboList1{ "-180deg", "-90deg", "0deg", "90deg", "180deg" };
        //QStringList _thetaComboList2{ "-360deg", "-180deg", "0deg", "90deg", "180deg" };
        //QStringList _thetaComboList3{ "0deg", "-270deg", "-180deg", "-90deg", "0deg", "90deg", "180deg", "270deg" };
        //QStringList _thetaComboList4{ "360deg", "270deg", "180deg", "90deg", "0deg", "-90deg", "-180deg", "-270deg" };
        //QList<QPair<QString, QList<QString>>> m_FixedVariableValueList = { {"theta", _thetaComboList1 }, { "phi", _thetaComboList2 }, { "degree", _thetaComboList3 }, { "fre", _thetaComboList4 } };

        //QList<QPair<QString, QList<double>>> dataList{};
        //auto data1 = qMakePair(QString("AAA"), QList<double>{ 1, 2, 3, 4, 5 });
        //auto data2 = qMakePair(QString("BBB"), QList<double>{ 2, 3, 4, 5, 6 });
        //auto data3 = qMakePair(QString("VVV"), QList<double>{ 3, 4, 5, 6, 7});
        //auto data4 = qMakePair(QString("CCC"), QList<double>{ 4, 5, 6, 7, 8 });
        //dataList << data1 << data2 << data3 << data4 << data1 << data2 << data3 << data4;

        ////顶级选择数据对话框
        //m_selecetDataDialog = new SelectDatatDialog();
        //m_selecetDataDialog->setFixedSize(400, 400);
        //m_selecetDataDialog->moveToCenter();
        //m_selecetDataDialog->show();
        //m_selecetDataDialog->setDialogTitle("方向性");
        //m_selecetDataDialog->setDataList(dataList);
        //m_selecetDataDialog->updateUI();

        //////次级选择数据对话框
        //DataChosenListDialog* m_dataChosenListDialog = new DataChosenListDialog(this);
        //m_dataChosenListDialog->setFixedSize(400, 400);
        //m_dataChosenListDialog->moveToCenter();
        //QList<QString> data{ "-180deg", "-90deg", "0deg", "90deg", "180deg" };
        //m_dataChosenListDialog->setData(data);
        //m_dataChosenListDialog->show();
        //m_dataChosenListDialog->updateUI();
        //QList<int> indexs{ 1, 2 };
        //m_dataChosenListDialog->setSelctedIndexs(indexs);

        //_aboutPage->show();
        m_customPlot = new Curve2DPlotor(this);
        m_customPlot->legend->setVisible(true);
        m_customPlot->legend->blockSignals(true);
        m_settings = new Graph2DSettings(this);
        //先连接信号和槽，然后设置m_settings的数值，以使其直接作用到m_customPlot
        initConnections();

        //m_settings->setCurrentFixedValueIndex(2);
        ////m_settings->setFixedVariableValue(m_FixedVariableValueList);
        //m_settings->setCategaryData({ "雷内","fe ","tianl" });
        m_settings->updateUILayout(); //布局
        /// @brief 测试代码结束

        slot_legendTitleFontFamilyChanged("宋体");
        slot_legendTitleFontSizeChanged(8);
        QSplitter* splitter = new QSplitter(Qt::Horizontal, this);
        splitter->addWidget(m_customPlot);
        splitter->addWidget(m_settings);
        splitter->setSizes({ 3000,1000 });
        layout->addWidget(splitter);
        //layout->addWidget(m_customPlot);
        //layout->addWidget(m_settings);
    }

    Graph2D::~Graph2D()
    {
        if (m_customPlot)
        {
            delete m_customPlot;
            m_customPlot = nullptr;
        }
    }

    void Graph2D::addLine(const QPair<QString, QVector<double>>& x,
        const QPair<QString, QVector<double>>& y)
    {
        QCPGraph* gta = m_customPlot->addGraph();

        //m_customPlot->removeGraph

            //设置颜色
        auto index = m_graphs.size() % m_colorList.size();
        auto color = m_colorList.at(index);
        QPen pen;
        pen.setWidth(3);
        pen.setColor(color);
        gta->setPen(pen);

        m_graphs.append(gta);
        gta->setData(x.second, y.second);
        gta->setName(y.first);
        //m_customPlot->xAxis->setLabel(x.first);
        //m_customPlot->yAxis->setLabel(y.first);
        m_customPlot->legend->setVisible(true);
        //if (m_graphs.size() == 1)//只有一个数据的时候
        //{
        //    gta->rescaleAxes();
        //}
        //else
        //{
        //    gta->rescaleAxes(true);
        //}

        //添加曲线名字
        m_settings->addCurveToList(y.first);
        //m_settings->setXAxisName(x.first);
        m_customPlot->rescaleAxes();
        m_customPlot->replot();
    }

    QCPGraph* Graph2D::addLine(const InfomationCurve2DBasical& info1)
    {
        InfomationCurve2DBasical info = info1;
        QCPGraph* gta = m_customPlot->addGraph();
        gta->setSelectable(QCP::SelectionType::stNone);
        //设置颜色
        auto index = m_graphs.size() % m_colorList.size();
        auto color = m_colorList.at(index);
        QPen pen;
        pen.setWidth(1);
        pen.setColor(color);
        gta->setPen(pen);

        m_graphs.append(gta);
        //qDebug() << " info.getYData().second =" << info.getYData().second;

        gta->setData(info.getXData().second, info.getYData().second);
        gta->setName(info.getYData().first);
        //每个m_customPlot的横纵轴与文件整体有关，不与单条曲线有关
        //m_customPlot->xAxis->setLabel(x.first);
        //m_customPlot->yAxis->setLabel(y.first);
        //m_customPlot->legend->setVisible(true);
        // 
        info.setCurveLineAddress(gta);//记录曲线地址
        //只有一个数据的时候,重置坐标轴
        m_graphs.size() == 1 ? gta->rescaleAxes() : gta->rescaleAxes(true);

        //添加曲线名字
        QStandardItem* item = m_settings->addCurveToList(info.getYData().first);
        m_curveMap[item] = info;//记录下来以备查找

        m_customPlot->replot();

        return gta;
    }

    bool Graph2D::saveScreenShot(const QString& path)
    {
        return m_customPlot->saveJpg(path);
    }

    // 设置框中选中的曲线发生改变->根据曲线信息更新m_settings
    void Graph2D::slot_chosenItemsChanged(const QList<QStandardItem*>& itemList)
    {
        QList<InfomationCurve2DBasical> curInfoList;
        for (const auto& i : itemList)
        {
            if (!m_curveMap.contains(i))
            {
                //todo 警告
                continue;
            }
            curInfoList.append(m_curveMap[i]);
        }

        if (curInfoList.isEmpty())
        {
            //折叠控制面板
            m_settings->hideCurvePropertylPanel();
        }
        else
        {
            //各个曲线信息的交集
            InfomationCurve2DBasical commonInfo;
            auto isSuc = InfomationCurve2DBasical::getCommonData(curInfoList, commonInfo);
            if (!isSuc)
            {
                //TODO 警告
                return;
            }
            m_settings->setCurvePropertyPanelState(commonInfo);
        }

    }

    void Graph2D::slot_updateCurveData(
        const QList<QStandardItem*>& itemList,
        const InfomationCurve2DBasical& changedInfo)
    {
        for (const auto& i : itemList)
        {
            if (!m_curveMap.contains(i))
            {
                //todo 警告
                continue;
            }

            auto& dataInfo = m_curveMap[i];
            if (!changedInfo.getIsMuti())//单选，更新固定值和value
            {
                dataInfo.setOtherKeyData(changedInfo.getOtherKeyData());
                dataInfo.setValueIndex(changedInfo.getValueIndex());
            }
            dataInfo.setIsDB(changedInfo.getIsDB());
            dataInfo.setIsNormalized(changedInfo.getIsNormalized());

            this->updateCurve(i, dataInfo);//更新而非新建
        }
    }

    void Graph2D::slot_legendTitleFontFamilyChanged(const QString& fontFamily)
    {

        auto font = m_customPlot->legend->font();
        font.setFamily(fontFamily);
        m_customPlot->legend->setFont(font);
        m_customPlot->replot();
    }

    void Graph2D::slot_legendTitleFontSizeChanged(int fontSize)
    {
        auto font = m_customPlot->legend->font();
        font.setPointSizeF(fontSize);
        m_customPlot->legend->setFont(font);
        m_customPlot->replot();
    }

    void Graph2D::slot_showHideCurve(const QPair<int, bool>& curveState)
    {
        auto curve = m_customPlot->graph(curveState.first);
        curve->setVisible(curveState.second);
        //curveState.second ? m_customPlot->legend->addItem(curve->name()) : m_customPlot->legend->removeItem(curveState.first);
        m_customPlot->rescaleAxes(true);
        m_customPlot->replot();
    }

    void Graph2D::initConnections()
    {
        connect(m_settings, &Graph2DSettings::signal_XAxisTitleNameChanged,
            this, [this](const QString& titleName) {m_customPlot->setXAxisTitleName(titleName); });
        connect(m_settings, &Graph2DSettings::signal_XAxisTitleFontFamilyChanged,
            this, [this](const QString& family) {m_customPlot->setXAxisFontFamily(family); });
        connect(m_settings, &Graph2DSettings::signal_XAxisTitleFontSizeChanged,
            this, [this](int size) {m_customPlot->setXAxisFontSize(size); });
        connect(m_settings, &Graph2DSettings::signal_XAxisMinValueChanged,
            this, [this](double minValue) {m_customPlot->setXAxisRangeMin(minValue); });
        connect(m_settings, &Graph2DSettings::signal_XAxisMaxValueChanged,
            this, [this](double maxValue) {m_customPlot->setXAxisRangeMax(maxValue); });
        connect(m_settings, &Graph2DSettings::signal_XAxisStepValueChanged,
            this, [this](double step) {m_customPlot->setXAxisRangeStep(step); });

        connect(m_settings, &Graph2DSettings::signal_YAxisTitleNameChanged,
            this, [this](const QString& titleName) {m_customPlot->setYAxisTitleName(titleName); });
        connect(m_settings, &Graph2DSettings::signal_YAxisTitleFontFamilyChanged,
            this, [this](const QString& family) {m_customPlot->setYAxisFontFamily(family); });
        connect(m_settings, &Graph2DSettings::signal_YAxisTitleFontSizeChanged,
            this, [this](int size) {m_customPlot->setYAxisFontSize(size); });
        connect(m_settings, &Graph2DSettings::signal_YAxisMinValueChanged,
            this, [this](double minValue) {m_customPlot->setYAxisRangeMin(minValue); });
        connect(m_settings, &Graph2DSettings::signal_YAxisMaxValueChanged,
            this, [this](double maxValue) {m_customPlot->setYAxisRangeMax(maxValue); });
        connect(m_settings, &Graph2DSettings::signal_YAxisStepValueChanged,
            this, [this](double step) {m_customPlot->setYAxisRangeStep(step); });

        connect(m_settings, &Graph2DSettings::signal_generateANewGraphCurve,
            this, &Graph2D::slot_generateANewGraphCurve);

        connect(m_settings, &Graph2DSettings::signal_chosenItemsChanged,
            this, &Graph2D::slot_chosenItemsChanged);
        connect(m_settings, &Graph2DSettings::signal_updateCurveData,
            this, &Graph2D::slot_updateCurveData);

        connect(m_settings, &Graph2DSettings::signal_legendTitleFontFamilyChanged,
            this, &Graph2D::slot_legendTitleFontFamilyChanged);
        connect(m_settings, &Graph2DSettings::signal_legendTitleFontSizeChanged,
            this, &Graph2D::slot_legendTitleFontSizeChanged);
        connect(m_customPlot->xAxis, QOverload< const QCPRange&>::of(&QCPAxis::rangeChanged), [this](const QCPRange& newRange) {
            m_settings->slot_xAxisRangeChange(newRange.lower, newRange.upper); });
        connect(m_customPlot->yAxis, QOverload< const QCPRange&>::of(&QCPAxis::rangeChanged), [this](const QCPRange& newRange) {
            m_settings->slot_yAxisRangeChange(newRange.lower, newRange.upper); });

        connect(m_settings, &Graph2DSettings::signal_showHideCurve,
            this, &Graph2D::slot_showHideCurve);
    }

    void Graph2D::updateCurve(QStandardItem* item, InfomationCurve2DBasical& info)
    {
        auto _graph = info.getGraph();
        auto _reader = info.getReader();
        QCPGraph* curveAdd = info.getCurveLineAddress();
        auto valueIndex = info.getValueIndex();
        if (curveAdd == nullptr || _graph == nullptr || _reader == nullptr)
        {
            // TODO 警告
            return;
        }
        _reader->setScanParameterIndex(info.getScanParameterIndex());

        auto otherKeyData = info.getOtherKeyData();
        QVector<QVector<double>> others;
        for (auto i : otherKeyData)
        {
            others.append(QVector<double>{i});
        }
        _reader->setOtherKeyParameter(others);

        QList<InfomationCurve2DBasical> newInfos;
        _reader->getChosenLinesFromKey(QList<int>{valueIndex}, newInfos);
        if (newInfos.size() != 1)
        {
            //TODO 警告， 应该只产生一组数据
            return;
        }
        auto xData = newInfos[0].getXData();
        auto yData = newInfos[0].getYData();
        //qDebug() << "yData =" << yData;
        info.setXData(xData);
        info.setYData(yData);

        // TODO 取对数和归一化 针对单条曲线
        normalizeAndLog(yData.second, info.getIsNormalized(), info.getIsDB());
        curveAdd->setData(xData.second, yData.second);
        curveAdd->setName(yData.first);
        item->setText(yData.first);

        m_customPlot->replot();
    }

    void Graph2D::slot_generateANewGraphCurve(const QList<QStandardItem*>& itemList,
        const InfomationCurve2DBasical& changedInfo)
    {
        QList<InfomationCurve2DBasical> newDataList;

        for (const auto& i : itemList)
        {
            if (!itemList.contains(i))
            {
                //todo 警告
                continue;
            }

            auto dataInfo = m_curveMap[i];
            auto _graph = dataInfo.getGraph();
            auto _reader = dataInfo.getReader();
            QCPGraph* curveAdd = dataInfo.getCurveLineAddress();

            if (curveAdd == nullptr || _graph == nullptr || _reader == nullptr)
            {
                // TODO 警告
                return;
            }

            auto changedScanName = changedInfo.getScanParameterName();
            auto keyNames = _reader->getEachColNameOfKey();
            auto newScanIndex = keyNames.indexOf(changedScanName);
            auto oldScanIndex = dataInfo.getScanParameterIndex();
            auto keyDataList = _reader->getEachColDataOfKey();
            //设置新的扫描参数
            if (newScanIndex == -1)
            {
                // TODO 警告
                return;
            }
            dataInfo.setScanParameterIndex(newScanIndex);

            //设置新的otherKeyList
            QVector<double> otherKeyVector = dataInfo.getOtherKeyData();
            otherKeyVector.insert(oldScanIndex, keyDataList[oldScanIndex][0]);
            otherKeyVector.removeAt(newScanIndex);

            _reader->setScanParameterIndex(newScanIndex);

            QVector<QVector<double>> tempOtherKey;
            for (auto i : otherKeyVector)
            {
                tempOtherKey.append(QVector<double> {i});
            }
            _reader->setOtherKeyParameter(tempOtherKey);
            QList<InfomationCurve2DBasical> newYList;
            _reader->getChosenLinesFromKey(QList<int>{dataInfo.getValueIndex()}, newYList);

            for (const auto& i : newYList)
            {
                newDataList.append(i);
            }
        }

        emit signal_generateANewGraphCurve(newDataList);
    }
}
